import { config } from '@/config'
import { WsConn } from './ws-conn'
import { modal, notify } from '@/widgets'
import { closeWindow } from '@/common'

export interface RemoteEvent<C extends string> {
  code: C
  seq: number
}

export type RemoteEventHandler<T extends RemoteEvent<string>> = (t: T) => void

class RemoteEventHandlerSet {
  private handlers: Record<string, RemoteEventHandler<any>[]> = {}
  private last_seq = -1

  public add<C extends string, T extends RemoteEvent<C>>(code: C, h: RemoteEventHandler<T>) {
    let i: RemoteEventHandler<T>[] = this.handlers[code] as RemoteEventHandler<T>[]
    if (!i) {
      i = []
      this.handlers[code] = i
    }
    i.push(h)
  }

  public del<C extends string, T extends RemoteEvent<C>>(code: C, h: RemoteEventHandler<T>) {
    const hs = this.handlers[code]
    if (hs) {
      const idx = hs.lastIndexOf(h)
      if (idx >= 0) {
        hs.splice(idx, 1)
      }
    }
  }
  public get<C extends string, T extends RemoteEvent<C>>(
    code: C
  ): Array<RemoteEventHandler<T>> | undefined {
    return this.handlers[code]
  }

  public notify<T extends RemoteEvent<any>>(evt: T) {
    if (evt.seq <= this.last_seq) {
      return
    }
    this.last_seq = evt.seq
    const handles = this.handlers[evt.code]
    if (!handles) {
      return
    }
    for (const h of handles) {
      try {
        h(evt)
      } catch (ex) {
        console.error(ex)
      }
    }
  }
}

const handlers = new RemoteEventHandlerSet()

export function onRemote<C extends string, E extends RemoteEvent<C>>(
  code: C,
  h: RemoteEventHandler<E>
) {
  handlers.add(code, h)
}

export function offRemote<C extends string, E extends RemoteEvent<C>>(
  code: C,
  h: RemoteEventHandler<E>
) {
  handlers.del(code, h)
}

function onMessage(str: string) {
  console.log('on ws-msg', str)
  const m = JSON.parse(str) as RemoteEvent<any>
  handlers.notify(m)
}

async function onConnectError() {
  const ok = await modal.confirm({
    title: '连接失败',
    content: '无法连接服务器,是否重新加载页面?',
    positiveText: '确定',
    negativeText: '关闭当前页面'
  })
  if (ok) {
    window.location.reload()
  } else {
    closeWindow()
  }
}

interface WebsocketConnectEvent extends RemoteEvent<'WebsocketConnectEvent'> {
  client_id: string
}

async function onWsConnEvt(evt: WebsocketConnectEvent) {
  if (evt.client_id === config.clientId) {
    return
  }
  const ok = await modal.confirm({
    title: '重复连接',
    content: '已经从其他页面打开该项目,是否关闭当前页面?',
    positiveText: '确定',
    negativeText: '取消'
  })
  if (ok) {
    closeWindow()
  }
}

let conn: WsConn

export async function setupWsConn() {
  onRemote('WebsocketConnectEvent', onWsConnEvt)
  conn = new WsConn({
    url: config.wsPath,
    maxErr: 5,
    pingInterval: 20000,
    onMessage,
    onConnectError
  })
  conn.start()
  await conn.waitForConnected(10000)
  notify.success({ content: '连接服务器!' })
}
